/*

    file:   driver h
    desc:   GRAPHICS DRIVER header 

    note:   graphics memories are mapped with driver_mmap
            driver_throw_scanline(   ) shifts out one video line to VIDEO_PORT, 5 clock cycles per one pixel 


    author: Jaromir Dvorak (md@unicode cz)

    This file is part of the AVGA platform.
    http://avga.prometheus4.com/


    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
  
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
*/


#ifndef _DRIVER_H_
#define _DRIVER_H_

#include "../config_hw.h"
#include "../config_screen.h"


/* ########## BEGIN OF USER CONFIGURABLE SECTION ########## */
#ifndef DRIVER_HWCONFIG
#define DRIVER_HWCONFIG

//
// Video bitstream will apear at upper 4 bits of this port. lower 4 bits can be used as input.
//
#define VIDEO_PORT              PORTD
#define VIDEO_DDR               DDRD
#define VIDEO_DEFAULT_DDR		0x08	//video default DDR mask

#endif
#ifndef DRIVER_SCREENCONFIG
#define DRIVER_SCREENCONFIG

////
//Reference table size
////
#define DRIVER_WIDTH                 24
#define DRIVER_HEIGHT                18

////
//Define how many upper blocks driver should look for in RAM 
////
#define DRIVER_RAM_BLOCK_COUNT       12

////
//Define height of block in pixels 
//note that block width is always 8, fixed 
////
#define DRIVER_BLOCK_HEIGHT          8

////
//Define if you want to enable horizontal scrolling 
//note: if scrolling is not needed at all, a simple version of the driver should be used 
////
#define HSCROLL			     1

////
//Define how many extra rows you want to use for vertical scrolling 
//e g  how many windows can be independetly vertically scrollable 
////
#define VSCROLL                      1


#endif
/* ########### END OF USER CONFIGURABLE SECTION ########### */




/*
 *
 * Low-level defined configuration combinations 
 *
 */

#ifdef  HSCROLL
#define DRIVER_COLUMNS              (DRIVER_WIDTH + 1)
#else
#define DRIVER_COLUMNS              (DRIVER_WIDTH)
#endif

#ifdef  VSCROLL
#define DRIVER_ROWS                 (DRIVER_HEIGHT + VSCROLL)
#else
#define DRIVER_ROWS                 (DRIVER_HEIGHT)
#endif

#define DRIVER_PGM_BLOCK_COUNT      (0xFF-DRIVER_RAM_BLOCK_COUNT)
#define DRIVER_BLOCK_SIZE           (DRIVER_BLOCK_HEIGHT * 4)

#ifndef __ASM__
#include <avr/pgmspace.h>




/*
 *
 * Drawing constants
 *
 */

//screen parameters
#define DRIVER_RESX                 (DRIVER_WIDTH * 8)
#define DRIVER_MAXX                 (DRIVER_COLUMNS * 8)
#define DRIVER_RESY                 (DRIVER_HEIGHT * DRIVER_BLOCK_HEIGHT)
#define DRIVER_MAXY                 (DRIVER_ROWS  * DRIVER_BLOCK_HEIGHT)
#define DRIVER_LAST_COLUMN          (DRIVER_WIDTH-1)
#define DRIVER_LAST_ROW             (DRIVER_HEIGHT-1)

//page size
#define DRIVER_REFTABLE_SIZE        (DRIVER_ROWS * DRIVER_COLUMNS)
#define DRIVER_SCREEN_SIZE          DRIVER_REFTABLE_SIZE
#define DRIVER_RAMMAP_SIZE          (DRIVER_BLOCK_SIZE * DRIVER_RAM_BLOCK_COUNT)

//NATIVE TILE width in pixels
//This is just a dummy definition for transparency.
//The system DOES NOT SUPPORT other values.
#define DRIVER_BLOCK_WIDTH           8




/*
 *
 * Real video pointers. Only graphic driver itself should access them directly.
 *
 */

uint8_t *_scrp;
PGM_P    _pgmp;
uint8_t *_ramp;
uint8_t *__ramp;



/*
 *
 * Video pointers for access in app.
 *
 */

#ifndef pgmpd
#define pgmpd _pgmp
#endif
#define driver_map_pgmp(pgmp) ({ pgmpd=pgmp; })
#define driver_set_tileset(ptr) driver_map_pgmp(ptr)

#ifndef scrpd
#define scrpd _scrp
#endif
#define driver_map_scrp(scrp) ({ scrpd=scrp; })
#define driver_set_reftable(ptr) driver_map_scrp(ptr)

#define rampd _ramp
#define driver_map_ramp(ramp) ({ _ramp=ramp; __ramp = ramp - DRIVER_PGM_BLOCK_COUNT * DRIVER_BLOCK_SIZE; })


/*
 *
 * Generic I/O macros.
 * Works with default video memory provided with  driver_mmap(...) function.
 *
 */
 
 
#ifndef EMPTY_BLOCK
#define EMPTY_BLOCK                               0
#endif

//returns back the default tileset
#define driver_get_tileset()			(pgmpd)
#define driver_get_pgmmap()			(pgmpd)

//returns back the default reference table
#define driver_get_reftable()			(scrpd)
#define driver_get_ptr()			(scrpd)

//returns back rammap
#define driver_get_ram_tileset()		(rampd)
#define driver_get_rammap()			(rampd)

//map the given block to ram
#define driver_rammap_block(x)          (DRIVER_PGM_BLOCK_COUNT + (x))

//map the given block to pgm
#define driver_pgmmap_block(x)          ((x))

//is the given block in ram?
#define driver_is_rammap(x)             ((x) >= DRIVER_PGM_BLOCK_COUNT)

//gets pointer to block at x,y
#define driver_get_block_ptr(x, y)      (&scrpd[(x)+(y)*DRIVER_COLUMNS])

//gets the block from x,y
#define driver_get_block(x, y)          (scrpd[(x)+(y)*DRIVER_COLUMNS])

//sets the block x,y to blk
#define driver_set_block(x,y, blk)      ({scrpd[(x)+(y)*DRIVER_COLUMNS] = (blk);})

//fill the whole screen with block blk
#define driver_fill(blk)                memset(scrpd, blk, DRIVER_REFTABLE_SIZE)

//clear the whole screen
#define driver_clear()                  driver_fill(EMPTY_BLOCK)

//prints RAM string
#define driver_print(x, y, txt)         ({ strdump(&driver_get_block((x),(y)), (txt)); })

//prints PGM string
#define driver_print_P(x, y, txt)       ({ strdump_P(&driver_get_block((x),(y)), (txt)); })

//allocate const string to PGM and print
#define driver_print_C(x, y, txt)       ({ driver_print_P(x, y, PSTR(txt)); })

//gets pointer to block i graphics in rammap
#define driver_get_ramblock_ptr(i)		(&rampd[i*DRIVER_BLOCK_SIZE])

//gets pointer to block i graphics in pgmmap
#define driver_get_pgmblock_ptr(i)		(&pgmpd[i*DRIVER_BLOCK_SIZE])




/*
 *
 * Some fast math
 *
 */

#define DIV8(x)   ((x)>>3)
#define MOD8(x)   ((x)&7)
#define MUL8(x)	  ((x)<<3)

#define DRIVER_X2COL(x)	DIV8(x)
#define DRIVER_COL2X(x) MUL8(x)
#define DRIVER_X2PRE(x)	MOD8(x)

#if DRIVER_BLOCK_HEIGHT == 8
#define DRIVER_Y2ROW(y)	DIV8(y)
#define DRIVER_ROW2Y(y) MUL8(y)
#define DRIVER_Y2PRE(y)	MOD8(y)
#else
#define DRIVER_Y2ROW(y)	((y)/DRIVER_BLOCK_HEIGHT)
#define DRIVER_ROW2Y(y) ((y)*DRIVER_BLOCK_HEIGHT)
#define DRIVER_Y2PRE(y)	((y)%DRIVER_BLOCK_HEIGHT)
#endif





/*
 *
 * In-line functions
 *
 */

//
// This will map memory areas for the graphics driver.
//
// scrp: Default reference table (pseudo-videoram) pointer.
//		 It is supposed that free ram space is available at this pointer with size DRIVER_REFTABLE_SIZE.
//		 This is not a rule, when using window-individual reference tables. In such case, it can be even NULL.
//		 All newly created windows will have this reference table by default.
//
//
// pgmp: Default PGM map (flash tileset) pointer. 
//		 This should point to FLASH at tile graphics.
//		 All newly created windows will have this tileset by default.
//
//
// ramp: RAM map (ram tileset) pointer. 
//		 It is supposed that free ram space is available on this pointer with size DRIVER_RAMMAP_SIZE.
//
//

#define driver_mmap(scrp, pgmp, ramp) 	\
{										\
	driver_map_pgmp(pgmp);				\
	driver_map_scrp(scrp);				\
	driver_map_ramp(ramp);				\
}										


/*
 *
 * Function prototypes.
 *
 */

void driver_throw_scanline(uint8_t line, uint8_t scroll);


/*
 *
 * Compatibility
 *
 */
#define MODE0_BLOCK_SIZE          DRIVER_BLOCK_SIZE
#define MODE0_ROWS                DRIVER_ROWS
#define MODE0_COLUMNS             DRIVER_COLUMNS
#define mode0_set_block(x,y,blk)  driver_set_block(x,y, blk)
#define mode0_get_block(x,y)      driver_get_block(x,y)
#define mode0_mmap(a,b,c)         driver_mmap(a,c,b)
#define mode0_rammap(x)           driver_rammap_block(x)
#define mode0_print(x,y,txt)      driver_print_C(x, y, txt)
#define mode0_cls()               driver_clear()
#define mode0_is_rammap(x)        driver_is_rammap(x)
#define mode0_pgmmap(x)           driver_pgmmap_block(x)
#define DIV10(x)                  ((x)/10)
#define MOD10(x)                  ((x)%10)


#endif // !__ASM__
#endif // !_DRIVER_H_
